#include "encode_util.h"
#include <iconv.h>
#include <string.h>
#include <iostream>
#include <codecvt>
#include <fstream>
#include <locale>
#include "log.h"

#define HTON16(x) ((((x) & 0xff00u) >> 1 * 8) | (((x) & 0x00ffu) << 1 * 8))

namespace encode_util
{
  // setlocale(LC_CTYPE, "");
  std::string UnicodeToUTF8(const std::wstring &wstr)
  {
    // std::wcerr << L"======================" << wstr;
    std::string ret;
    try
    {
      std::wstring_convert<std::codecvt_utf8<wchar_t>> wcv;
      ret = wcv.to_bytes(wstr);
    }
    catch (const std::exception &e)
    {
      std::cerr << e.what() << std::endl;
    }
    return ret;
  }

  std::wstring UTF8ToUnicode(const std::string &str)
  {
    std::wstring ret;
    try
    {
      std::wstring_convert<std::codecvt_utf8<wchar_t>> wcv;
      ret = wcv.from_bytes(str);
    }
    catch (const std::exception &e)
    {
      std::cerr << e.what() << std::endl;
    }
    return ret;
  }

  std::string UnicodeToANSI(const std::wstring &wstr)
  {
    std::string ret;
    std::mbstate_t state = {};
    const wchar_t *src = wstr.data();
    size_t len = std::wcsrtombs(nullptr, &src, 0, &state);
    if (static_cast<size_t>(-1) != len)
    {
      std::unique_ptr<char[]> buff(new char[len + 1]);
      len = std::wcsrtombs(buff.get(), &src, len, &state);
      if (static_cast<size_t>(-1) != len)
      {
        ret.assign(buff.get(), len);
      }
    }
    return ret;
  }

  std::wstring ANSIToUnicode(const std::string &str)
  {
    std::wstring ret;
    std::mbstate_t state = {};
    const char *src = str.data();
    size_t len = std::mbsrtowcs(nullptr, &src, 0, &state);
    if (static_cast<size_t>(-1) != len)
    {
      std::unique_ptr<wchar_t[]> buff(new wchar_t[len + 1]);
      len = std::mbsrtowcs(buff.get(), &src, len, &state);
      if (static_cast<size_t>(-1) != len)
      {
        ret.assign(buff.get(), len);
      }
    }
    return ret;
  }

  std::string UTF8ToANSI(const std::string &str)
  {
    return UnicodeToANSI(UTF8ToUnicode(str));
  }

  std::string ANSIToUTF8(const std::string &str)
  {
    return UnicodeToUTF8(ANSIToUnicode(str));
  }

  static uint8_t kBase64Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  static uint8_t kBase64Decode[] = {
      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
      255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
      15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
      255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
      41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255};

  bool IsGbk(const u_char *data, size_t len, int *character_count)
  {
    size_t i = 0;
    while (i < len)
    {
      if (data[i] <= 0x7f)
      { // 编码小于等于127,只有一个字节的编码，兼容ASCII
        i++;
        if (character_count != NULL)
        {
          *character_count = *character_count + 1;
        }
        continue;
      }
      else
      { // 大于127的使用双字节编码
        if (data[i] >= 0x81 &&
            data[i] <= 0xfe &&
            data[i + 1] >= 0x40 &&
            data[i + 1] <= 0xfe &&
            data[i + 1] != 0xf7)
        {
          i += 2;
          if (character_count != NULL)
          {
            *character_count = *character_count + 1;
          }
          continue;
        }
        else
        {
          return false;
        }
      }
    }
    return true;
  }

  bool MaskGbk(u_char *data, size_t len, int character_count, int front_count, int back_count)
  {
    std::string temp;
    temp.reserve(len);

    size_t i = 0;
    int character_index = 0;
    while (i < len)
    {
      if (data[i] <= 0x7f)
      { // 编码小于等于127,只有一个字节的编码，兼容ASCII
        if (character_index >= front_count && character_index < (character_count - back_count))
        {
          temp.push_back('*');
        }
        else
        {
          temp.push_back(data[i]);
        }
        character_index++;
        i++;
        continue;
      }
      else
      {
        // 大于127的使用双字节编码
        if (data[i] >= 0x81 &&
            data[i] <= 0xfe &&
            data[i + 1] >= 0x40 &&
            data[i + 1] <= 0xfe &&
            data[i + 1] != 0xf7)
        {
          if (character_index >= front_count && character_index < (character_count - back_count))
          {
            temp.push_back('*');
          }
          else
          {
            temp.push_back(data[i]);
            temp.push_back(data[i + 1]);
          }
          character_index++;
          i += 2;
          continue;
        }
        else
        {
          return false;
        }
      }
    }

    size_t temp_len = temp.size();
    for (size_t i = 0; i < len; ++i)
    {
      if (i < temp_len)
      {
        data[i] = temp[i];
      }
      else
      {
        // 由于将两个字节的中文字符转成一个字节的‘*’导致长度变短
        // 故在末尾添加空格字符使长度不变
        data[i] = ' ';
      }
    }
    return true;
  }

  bool IsUtf8(const u_char *data, size_t len, int *character_count)
  {
    // UTF8可用1-6个字节编码,ASCII用一个字节
    size_t i = 0;
    int bytes = 0;
    u_char ch = 0;
    while (i < len)
    {
      ch = *(data + i);
      if (bytes == 0)
      {
        if ((ch & 0x80) != 0)
        {
          while ((ch & 0x80) != 0)
          {
            ch <<= 1;
            bytes++;
          }
          if ((bytes < 2) || (bytes > 6))
          {
            return false;
          }
          bytes--;
        }
        if (character_count != NULL)
        {
          *character_count = *character_count + 1;
        }
      }
      else
      {
        if ((ch & 0xc0) != 0x80)
        {
          return false;
        }
        bytes--;
      }
      i++;
    }
    return (bytes == 0);
  }

  bool MaskUtf8(u_char *data, size_t len, int character_count, int front_count, int back_count)
  {
    std::string temp;
    temp.reserve(len);

    // UTF8可用1-6个字节编码,ASCII用一个字节
    size_t i = 0;
    int bytes = 0;
    u_char ch = 0;
    int character_index = 0;
    while (i < len)
    {
      ch = *(data + i);
      if (bytes == 0)
      {
        if ((ch & 0x80) != 0)
        { // 非ASCII字符的第一个字节
          while ((ch & 0x80) != 0)
          {
            ch <<= 1;
            bytes++;
          }
          if ((bytes < 2) || (bytes > 6))
          {
            return false;
          }
          if (character_index >= front_count && character_index < (character_count - back_count))
          {
            temp.push_back('*');
          }
          else
          {
            temp.push_back(data[i]);
          }
          bytes--;
        }
        else
        { // ASCII字符的字节
          if (character_index >= front_count && character_index < (character_count - back_count))
          {
            temp.push_back('*');
          }
          else
          {
            temp.push_back(data[i]);
          }
          character_index++;
        }
      }
      else
      { // 非ASCII字符的非第一个字节
        if ((ch & 0xc0) != 0x80)
        {
          return false;
        }
        if (character_index >= front_count && character_index < (character_count - back_count))
        {
          // 忽略这个字符
        }
        else
        {
          temp.push_back(data[i]);
        }
        bytes--;
        if (bytes == 0)
        {
          character_index++;
        }
      }
      i++;
    }

    size_t temp_len = temp.size();
    for (size_t i = 0; i < len; ++i)
    {
      if (i < temp_len)
      {
        data[i] = temp[i];
      }
      else
      {
        // 由于将两个字节的中文字符转成一个字节的‘*’导致长度变短
        // 故在末尾添加空格字符使长度不变
        data[i] = ' ';
      }
    }
    return true;
  }

  void Ucs2ToUtf8(std::string &out_str, const uint8_t *ucs2, size_t ucs2_len, bool big_endian)
  {
    // 注意：linux下wchar_t是4byte
    std::wstring wide_str;
    for (size_t i = 0; i < ucs2_len; i++)
    {
      uint16_t ucs_char = *(uint16_t *)(ucs2 + i * sizeof(uint16_t));
      if (big_endian)
      {
        ucs_char = HTON16(ucs_char);
      }
      wide_str.push_back((wchar_t)ucs_char);
    }
    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    out_str = converter.to_bytes(wide_str);
  }

  void GbkToUtf8(std::string &out_str, const char *gbk_data)
  {
    iconv_t cd = iconv_open("utf8", "gbk");
    if (cd == 0)
    {
      return;
    }

    char **pin = (char **)&gbk_data;
    size_t src_len = strlen(gbk_data);

    size_t dst_len = src_len * 2 + 1;
    char *dst_str = new char[dst_len];
    char *dst_temp = dst_str;

    memset(dst_str, 0, dst_len);

    if (iconv(cd, pin, &src_len, &dst_str, &dst_len) == 0xFFFFFFFF)
    {
      iconv_close(cd);
      delete[] dst_temp;
      return;
    }

    iconv_close(cd);
    out_str = dst_temp;
    delete[] dst_temp;
  }

  std::string Base64Encode(const uint8_t *text, uint32_t text_len)
  {
    std::string encode;
    uint32_t i;
    for (i = 0; i + 3 <= text_len; i += 3)
    {
      encode += kBase64Encode[text[i] >> 2];                                     // 取出第一个字符的前6位并找出对应的结果字符
      encode += kBase64Encode[((text[i] << 4) & 0x30) | (text[i + 1] >> 4)];     // 将第一个字符的后2位与第二个字符的前4位进行组合并找到对应的结果字符
      encode += kBase64Encode[((text[i + 1] << 2) & 0x3c) | (text[i + 2] >> 6)]; // 将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符
      encode += kBase64Encode[text[i + 2] & 0x3f];                               // 取出第三个字符的后6位并找出结果字符
    }

    if (i < text_len)
    {
      uint32_t tail = text_len - i;
      if (tail == 1)
      {
        encode += kBase64Encode[text[i] >> 2];
        encode += kBase64Encode[(text[i] << 4) & 0x30];
        encode += '=';
        encode += '=';
      }
      else // tail==2
      {
        encode += kBase64Encode[text[i] >> 2];
        encode += kBase64Encode[((text[i] << 4) & 0x30) | (text[i + 1] >> 4)];
        encode += kBase64Encode[(text[i + 1] << 2) & 0x3c];
        encode += '=';
      }
    }
    return encode;
  }

  std::string Base64Decode(const uint8_t *code, uint32_t code_len)
  {
    if ((code_len & 0x03) != 0)
    { // 如果它的条件返回错误，则终止程序执行。4的倍数。
      return "";
    }

    std::string plain;
    uint32_t i = 0;
    uint8_t quad[4] = {0};
    for (i = 0; i < code_len; i += 4)
    {
      for (uint32_t k = 0; k < 4; k++)
      {
        quad[k] = kBase64Decode[code[i + k]]; // 分组，每组四个分别依次转换为base64表内的十进制数
      }

      plain += (quad[0] << 2) | (quad[1] >> 4); // 取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的前2位进行组合

      if (quad[2] >= 64)
        break;
      else if (quad[3] >= 64)
      {
        plain += (quad[1] << 4) | (quad[2] >> 2); // 取出第二个字符对应base64表的十进制数的后4位与第三个字符对应base64表的十进制数的前4位进行组合
        break;
      }
      else
      {
        plain += (quad[1] << 4) | (quad[2] >> 2);
        plain += (quad[2] << 6) | quad[3]; // 取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合
      }
    }
    return plain;
  }

  bool isalpha(wchar_t ch)
  {
    if (ch >= L'A' && ch <= L'Z')
    {
      return true;
    }
    else if (ch >= L'a' && ch <= L'z')
    {
      return true;
    }
    else if(ch>>7){
      return true;
    }
    else
    {
      return false;
    }
  }

} // namespace encode_util